from soj.settings.execute.windows import WINEXE_PATH
from soj.settings.execute.common import MAX_TIMELIMIT,MAX_MEMORYLIMIT
from soj.builtin.execute.common import is_file,ensure_file,ExecutorResult,ExecutionResult
from pathlib import Path
import psutil as ps
import subprocess as sp
import json
from soj.common.judge import JudgeResultCode

class WinexeExecutor:
    type="winexe"

    def __init__(self,executable:Path,time:int,memory:int,input:Path,
                output:Path,error:Path,report:Path,args:list[str]=[]):
        ensure_file(executable)
        ensure_file(input)
        ensure_file(output)
        ensure_file(error)
        ensure_file(report)
        try:
            time=int(time);memory=int(memory)
        except Exception as e:
            raise TypeError(f"Unable to cast time limit or memory limit to integer") from e
        if time<0 or time>MAX_TIMELIMIT:
            raise ValueError(f"Time limit is not in range [{0},{MAX_TIMELIMIT}]")
        if memory<0 or memory>MAX_MEMORYLIMIT:
            raise ValueError(f"Memory limit is not in")
        self.executable=executable
        self.time=time
        self.memory=memory
        self.input=input
        self.output=output
        self.error=error
        self.report=report
        self.args=args

    def execute(self)->ExecutorResult:
        result:sp.CompletedProcess=sp.run(
            args=[WINEXE_PATH,self.executable,
                  str(self.time),
                  str(self.memory),
                  self.input,
                  self.output,
                  self.error,
                  self.report]+self.args,
            executable=WINEXE_PATH)
        return {
            'error_file':self.error,
            'executor_exit_code':result.returncode,
            'input_file':self.input,
            'output_file':self.output,
            'report_file':self.report
        }
    
    def read_report(self)->ExecutionResult:
        ensure_file(self.report)
        try:
            with open(self.report,"r") as f:
                result=json.loads(f.read())
                if result["internal_error"]:
                    status=JudgeResultCode.SYSTEM_ERROR
                elif result['is_tle']:
                    status=JudgeResultCode.TIME_LIMIT_EXCEEDED
                elif result['is_mle']:
                    status=JudgeResultCode.MEMORY_LIMIT_EXCEEDED
                elif result["exit_code"]!=0:
                    status=JudgeResultCode.RUNTIME_ERROR
                else:
                    status=JudgeResultCode.ACCEPTABLE
                    # note it not means the output is correct now
                return {
                    'exit_code':result['exit_code'],
                    'time':result['time'],
                    'memory':result['memory'],
                    'status':status
                }
        except OSError as e:
            raise OSError("Failed to open report file") from e
        except (json.JSONDecodeError,KeyError) as e:
            raise ValueError("Invalid report file content")
        except Exception as e:
            raise RuntimeError("Failed to load result from report file")
